import parole
import random

class Language(object):

    availableVowels = [
            'a', 'e', 'i', 'o', 'u', 'y', 'ai', 'ae', 'ia', 'eu', 'ie', 'ei',
            'au', 'ao', 'oi', 'io'
        ]

    stops = [
            'p', 't', 'k', 'b', 'd', 'g', 'q',
        ]

    fricatives = [
            's', 'z', 'sh', 'zh', 'th', 'dh', 'kh', 'gh', 'f', 'v',         
        ]

    affricates = [
            'ts', 'dz', 'ps', 'ks', 'pf', 'psh', 'dzh', 'tsh'
        ]


    sonorants = [
            'm', 'n', 'l', 'w', 'j', 'r'
        ]

    minVowels = 3
    maxVowels = 12
    minConsonants = 6
    maxConsonants = 24

    def __init__(self, meanings):
        self.meanings = list(meanings)
        random.shuffle(self.meanings)
        self.vowels = random.sample(Language.availableVowels,
                random.randint(Language.minVowels, Language.maxVowels))
        self.consonants = random.sample(
                Language.stops + Language.fricatives + Language.affricates + \
                Language.sonorants,
                random.randint(Language.minConsonants, Language.maxConsonants))

        self.onsetProb = random.random()
        self.codaProb = random.random()
        self.badOnsets = random.randint(0, 1) and random.sample(self.consonants,
                random.randint(1, len(self.consonants)/3)) or []
        self.badCodas = random.randint(0, 1) and random.sample(self.consonants,
                random.randint(1, len(self.consonants)/3)) or []

        self.morphemeLengthDistr = ((1,) * random.randint(2,6)) + \
                                   ((2,) * random.randint(0,4))# + \
                                   #((3,) * random.randint(0,2))

        self.hiatusProb = random.random() * 0.5
        self.wordBoundaryProb = 0.2 + 0.8*random.random()
        self.morphemes = {} # meaning -> morpheme

    def generateSyllable(self):
        parole.debug('Generating syllable...')
        nucleus = random.choice(self.vowels)
        syllable = nucleus
        ons = None
        if random.random() <= self.onsetProb:
            onsTries = 0
            while onsTries < 100 and (not ons) or ons in self.badOnsets:
                ons = random.choice(self.consonants)
                onsTries += 1
            if ons in Language.stops and random.choice((0,1)):
                try:
                    ons += random.choice([c for c in self.consonants if c in \
                        Language.sonorants])
                except IndexError:
                    pass
            elif ons in Language.fricatives and random.choice((0,1)):
                try:
                    ons += random.choice([c for c in self.consonants if c in \
                        Language.sonorants + Language.stops])
                except IndexError:
                    pass

            syllable = ons + syllable

        coda = None
        if random.random() <= self.codaProb:
            codaTries = 0
            while codaTries < 100 and (not coda) or coda in self.badCodas:
                coda = random.choice(self.consonants)
                codaTries += 1
            if coda in Language.sonorants and random.choice((0,1)):
                try:
                    coda += random.choice([c for c in self.consonants if c in \
                        Language.stops + Language.fricatives])
                except IndexError:
                    pass
            elif coda in Language.fricatives and random.choice((0,1)):
                try:
                    coda += random.choice([c for c in self.consonants if c in \
                        Language.stops])
                except IndexError:
                    pass

            syllable += coda

        parole.debug('...Generated syllable.')
        return syllable#, (ons, nucleus, coda)

    def generateMorpheme(self):
        parole.debug('Generating morpheme...')
        numSyllables = random.choice(self.morphemeLengthDistr)
        morpheme = self.generateSyllable()
        i = 1
        hiatusTries = 0
        while i < numSyllables:
            syl = self.generateSyllable()
            if morpheme[-1] in self.vowels and syl[0] in self.vowels and \
                    random.random() > self.hiatusProb and hiatusTries < 100:
                hiatusTries += 1
                continue
            else:
                morpheme += syl
                i += 1

        parole.debug('...Generated morpheme.')
        return (random.random() <= self.wordBoundaryProb and ' ' or '') + \
                morpheme

    def getForm(self, meanings):
        parole.debug('Getting form...')
        form = ''
        meanings = list(meanings)
        for meaning in self.meanings:
            while meaning in meanings:
                meanings.remove(meaning)
                if meaning not in self.morphemes:
                    morpheme = None
                    tries = 0
                    while tries < 100 and (not morpheme) or morpheme in self.morphemes.values():
                        morpheme = self.generateMorpheme()
                        tries += 1
                    self.morphemes[meaning] = morpheme
                form += self.morphemes[meaning]
        parole.debug('...got form: %r', form.strip())
        return form.strip()
